﻿using Nemerle;
using Nemerle.Assertions;
using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Linq;

using Nemerle2.Compiler;
using Microsoft.Cci;

namespace MetadataReader.CCI
{
  class CciPropertyInfo : CciMemberInfo, IPropertyInfo
  {
    public this([NotNull] declType : CciTypeInfo, [NotNull] propertyDef : IPropertyDefinition, index : int)
    {
      base(declType, propertyDef, index);
    }

    public sealed override Type : Nemerle2.Compiler.FixedType
    {
    	get { Provider.GetType(PropertyDefinition.Type) }
    }

    internal PropertyDefinition : IPropertyDefinition
    {
      get { Definition :> IPropertyDefinition }
    }

    public sealed override MemberKind  : MemberKind { get { MemberKind.Property } }

    public IsIndexer : bool
    {
      [Memoize] get { PropertyDefinition.Parameters.Any() }
    }

	  public IsMutable : bool
	  {
	    [Memoize] // Bogdan : It was Setter.HaseValue but it was initializing Getter
	    get { PropertyDefinition.Setter != null }
	  }


    private GetAccessor(accessor : IMethodReference) : ValueOption[IMethodInfo]
    {
      ret:
        {
          match (accessor)
          {
            | null => ValueOption()
            | _    =>
              def intKey = accessor.ResolvedMethod.InternedKey;

              foreach (method is CciMethodInfo in DeclaringCciType.GetMembers())
                when (method.InternedKey == intKey)
                  ret(ValueOption(method));

              assert(false);
          }
        }
    }

	  public Getter : ValueOption[IMethodInfo]
	  {
	    [Memoize] get { GetAccessor(PropertyDefinition.Getter) }
	  }

	  public Setter : ValueOption[IMethodInfo]
	  {
	    [Memoize] get { GetAccessor(PropertyDefinition.Setter) }
	  }

	  public sealed override IsAbstract : bool
	  {
	    [Memoize]
	    get
	    {
	      def accessor =
	        if (PropertyDefinition.Getter != null)
	          PropertyDefinition.Getter
	        else if (PropertyDefinition.Setter != null)
	          PropertyDefinition.Setter
	        else
	          assert(false, "It is incorrect property");

	      accessor.ResolvedMethod.IsAbstract
	    }
	  }

	  public sealed override IsStatic : bool
	  {
	    [Memoize] // Bogdan: Do we need memoization here?
	    get
	    {
	      def accessor =
	        if (PropertyDefinition.Getter != null)
	          PropertyDefinition.Getter
	        else if (PropertyDefinition.Setter != null)
	          PropertyDefinition.Setter
	        else
	          assert(false, "It is incorrect property");

	      accessor.ResolvedMethod.IsStatic
	    }
	  }

	  public override ToString() : string
	  {
	    $"Property: $Name : $(Getter.Value.ReturnType)";
	  }
  }
}
